package com.irenty.effectivej.ch02.objectreation;

import java.util.Arrays;
import java.util.EmptyStackException;
import java.util.logging.Logger;

import org.testng.annotations.Test;

/*
 * Item 6: Eliminate obsolete object references
 * obsolete - przestarzaly, zdezaktualizowany
 */
public class EliminateObsoleteObjectCreation {
	private final static Logger LOGGER = Logger
			.getLogger(EliminateObsoleteObjectCreation.class.getName());

	/*
	 * If a stack grows and then shrinks, the objects that were popped off the
	 * stack will not be garbage collected, even if the program using the stack
	 * has no more references to them. This is because the stack maintains
	 * obsolete references to these objects. An obsolete reference is simply a
	 * refer- ence that will never be dereferenced again. In this case, any
	 * references outside of the “active portion” of the element array are
	 * obsolete. The active portion consists of the elements whose index is less
	 * than size.
	 */
	private static class Stack {
		private Object[] elements;
		private int size = 0;
		private static final int DEFAULT_INITIAL_CAPACITY = 16;

		public Stack() {
			elements = new Object[DEFAULT_INITIAL_CAPACITY];
		}

		public void push(Object e) {
			ensureCapacity();
			elements[size++] = e;
		}

		public Object pop() {
			if (size == 0)
				throw new EmptyStackException();
			return elements[--size];
		}

		/*
		 * Generally speaking, whenever a class manages its own memory, the pro-
		 * grammer should be alert for memory leaks. Whenever an element is
		 * freed, any object references contained in the element should be
		 * nulled out.
		 */
		public Object popGOOD() {
			if (size == 0)
				throw new EmptyStackException();
			Object result = elements[--size];
			elements[size] = null; // Eliminate obsolete reference
			return result;
		}

		/**
		 * Ensure space for at least one more element, roughly doubling the
		 * capacity each time the array needs to grow.
		 */
		private void ensureCapacity() {
			if (elements.length == size)
				elements = Arrays.copyOf(elements, 2 * size + 1);
		}
	}

	/*
	 * The storage pool consists of the elements of the elements array (the
	 * object refer- ence cells, not the objects themselves). The elements in
	 * the active portion of the array (as defined earlier) are allocated, and
	 * those in the remainder of the array are free. The garbage collector has
	 * no way of knowing this; to the garbage collector, all of the object
	 * references in the elements array are equally valid. Only the pro- grammer
	 * knows that the inactive portion of the array is unimportant. The pro-
	 * grammer effectively communicates this fact to the garbage collector by
	 * manually nulling out array elements as soon as they become part of the
	 * inactive portion
	 */

	@Test
	public void testMemoryLeak() throws Exception {
		Stack s = new Stack();

	}

	/*
	 * Another common source of memory leaks is caches.
	 * 
	 * Several solutions: - Is an entry is relevant exactly so long as there are
	 * references to its key outside of the cache, represent the cache as a
	 * WeakHashMap; entries will be removed automatically after they become
	 * obsolete. - More commonly, the useful lifetime of a cache entry is less
	 * well defined, with entries becoming less valuable over time. Under these
	 * circumstances, the cache should occasionally be cleansed of entries that
	 * have fallen into disuse. This can be done by a background thread or as a
	 * side effect of adding new entries to the cache. For example The
	 * LinkedHashMap class facilitates the latter approach with its
	 * removeEldestEntry method
	 */

	/*
	 * A third common source of memory leaks is listeners and other callbacks.
	 * If you implement an API where clients register callbacks but don’t
	 * deregister them explicitly, they will accumulate unless you take some
	 * action.
	 */
}
